

#include <wchar.h>
#include "Parser.h"
#include "Scanner.h"




void Parser::SynErr(int n) {
	if (errDist >= minErrDist) errors->SynErr(la->line, la->col, n);
	errDist = 0;
}

void Parser::SemErr(const wchar_t* msg) {
	if (errDist >= minErrDist) errors->Error(t->line, t->col, msg);
	errDist = 0;
}

void Parser::Get() {
	for (;;) {
		t = la;
		la = scanner->Scan();
		if (la->kind <= maxT) { ++errDist; break; }

		if (dummyToken != t) {
			dummyToken->kind = t->kind;
			dummyToken->pos = t->pos;
			dummyToken->col = t->col;
			dummyToken->line = t->line;
			dummyToken->next = NULL;
			coco_string_delete(dummyToken->val);
			dummyToken->val = coco_string_create(t->val);
			t = dummyToken;
		}
		la = t;
	}
}

void Parser::Expect(int n) {
	if (la->kind==n) Get(); else { SynErr(n); }
}

void Parser::ExpectWeak(int n, int follow) {
	if (la->kind == n) Get();
	else {
		SynErr(n);
		while (!StartOf(follow)) Get();
	}
}

bool Parser::WeakSeparator(int n, int syFol, int repFol) {
	if (la->kind == n) {Get(); return true;}
	else if (StartOf(repFol)) {return false;}
	else {
		SynErr(n);
		while (!(StartOf(syFol) || StartOf(repFol) || StartOf(0))) {
			Get();
		}
		return StartOf(syFol);
	}
}

void Parser::coffeec() {
		cube = semanticCube::semanticCube();
		classDir = classDirectory::classDirectory();
		code = intermediateCode::intermediateCode();
		constantTable = constVariableTable::constVariableTable(BASE_CONST,CONST_JUNK_SIZE);
		contProc = 0;
		objMet = false;
		sJump.push(2);
		
												code.insertCuadruplo(20,-1,-1,-1);
												code.insertCuadruplo(16,-1,-1,-1);
											
		COFFEEC1();
		Expect(2);
		code.fillCuadruplo(sJump.pop(), code.getCounter()); 
		
		DECLARACION_CLASE();
		Expect(74);
		CLASE1();
		sJump.push(code.getCounter());
		code.insertCuadruplo(16,-1,-1,-1);
		
		CLASE2();
		CLASE3();
		METODO_MAIN();
		Expect(75);
		constantTable.saveTable();
		code.saveCuadruplo();
		
}

void Parser::COFFEEC1() {
		if (la->kind == 3) {
			DECLARACION_CLASE();
			Expect(74);
			CLASE();
			Expect(75);
			COFFEEC1();
		} else if (la->kind == 2) {
		} else SynErr(89);
}

void Parser::DECLARACION_CLASE() {
		Expect(3);
		Expect(1);
		qAuxClass.enqueue(t->val);
		
		DECLARACION_CLASE1();
		const wchar_t* idClass = qAuxClass.dequeue();
		const wchar_t* fatherClass;
		if (!classDir.exist(idClass, L"id")) {
			procedureDirectory *dir = new procedureDirectory::procedureDirectory();
			if (qAuxClass.isEmpty()) {
				fatherClass = L"None";
			} else {
				fatherClass = qAuxClass.dequeue();
				if (classDir.exist(fatherClass, L"fatherId")) {
					procedureDirectory *dad = classDir.getElement(fatherClass).procDir;
					dad->insertIntoDir(dir);
				} else {
					wcout << L"ERROR. Clase padre inexistente.\n";
				}
			}
		
													queue<const wchar_t*> *params = new queue<const wchar_t*>;
		
													variablesTable *vars = new variablesTable::variablesTable(contProc, BASE_MEM, MEM_JUNK_SIZE);
													dir->insertProcedure(L"global", L"public", false, L"", *params, L"global", *vars, code.getCounter());
													code.insertCuadruplo(19, -1, -1, contProc++);
			//										code.insertCuadruplo(20, -1, -1, -1);
		
		
													classDir.insertClass(idClass, fatherClass, *dir);
													currentClass = idClass;
													procDir = dir;
													currentProc = L"global";
													contTemp[0] = BASE_TEMP;
													contTemp[1] = BASE_TEMP + TEMP_JUNK_SIZE;
													contTemp[2] = BASE_TEMP + (2 * TEMP_JUNK_SIZE);
													contTemp[3] = BASE_TEMP + (3 * TEMP_JUNK_SIZE);
													varTable = vars;
												} else {
													wcout << L"ERROR. La clase " << idClass << L" ya existe.\n";
												}
												
}

void Parser::CLASE1() {
		if (la->kind == 12) {
			DECLARACION_VARIABLES();
			VAR_CLASE();
			CLASE1();
		} else if (StartOf(1)) {
		} else SynErr(90);
}

void Parser::CLASE2() {
		if (la->kind == 5) {
			CONSTRUCTOR();
			code.insertCuadruplo(24,-1,-1,-1);
			
			CLASE2();
		} else if (la->kind == 2 || la->kind == 6 || la->kind == 75) {
		} else SynErr(91);
}

void Parser::CLASE3() {
		if (la->kind == 6) {
			METODO();
			code.insertCuadruplo(24,-1,-1,-1);
			
			CLASE3();
		} else if (la->kind == 2 || la->kind == 75) {
		} else SynErr(92);
}

void Parser::METODO_MAIN() {
		Expect(2);
		queue<const wchar_t*> *params = new queue<const wchar_t*>;
		code.fillCuadruplo(sJump.pop(), code.getCounter()); 
		variablesTable *vars = new variablesTable::variablesTable(contProc, BASE_MEM, MEM_JUNK_SIZE);
		procDir->insertProcedure(L"main", L"public", false, L"", *params, L"global", *vars, code.getCounter());
		code.insertCuadruplo(19, -1, -1, contProc++);
		//						code.insertCuadruplo(20, -1, -1, -1);
		
									currentProc = L"main";
									varTable = vars;
		
									contTemp[0] = BASE_TEMP;
									contTemp[1] = BASE_TEMP + TEMP_JUNK_SIZE;
									contTemp[2] = BASE_TEMP + (2 * TEMP_JUNK_SIZE);
									contTemp[3] = BASE_TEMP + (3 * TEMP_JUNK_SIZE);
								
		Expect(74);
		BLOQUE();
		Expect(75);
}

void Parser::CLASE() {
		CLASE1();
		code.insertCuadruplo(24,-1,-1,-1);
		
		CLASE2();
		CLASE3();
}

void Parser::DECLARACION_CLASE1() {
		if (la->kind == 4) {
			Get();
			Expect(45);
			Expect(76);
			Expect(1);
			qAuxClass.enqueue(t->val);
			
			Expect(77);
		} else if (la->kind == 74) {
		} else SynErr(93);
}

void Parser::DECLARACION_VARIABLES() {
		variablesTable *table = procDir->getElement(currentProc).varTable;
		
		Expect(12);
		DECLARACION_VARIABLES2();
		S_TIPO();
		Expect(1);
		if (!table->exist(t->val)) {
		qAuxClass.enqueue(t->val);
		} else {
			wcout << L"ERROR. La variable "<< t->val << L" ya existe\n";
		}
		
		DECLARACION_VARIABLES1();
		const wchar_t* access = qAuxClass.dequeue();
		const wchar_t* type = qAuxClass.dequeue();
		if(!wcscmp(type,L"object")) {
			type = qAuxClass.dequeue();
			sType.push(type);
			procedureDirectory *tDir = classDir.getElement(type).procDir;
			variablesTable *tVar = tDir->getElement(L"global").varTable;
			variablesTable *obj;
			while(!qAuxClass.isEmpty()) {
				obj = new variablesTable(table->contInt, table->contFloat, table->contBoolet, table->contChar);
				tVar->insertIntoTable(obj);
				table->insertObject(qAuxClass.dequeue(), type, access, *obj);
			}
		} else {
			sType.push(type);
			if(type == L"list") {
				//creacion de lista usando auxListLength
			}
			const wchar_t* id;
			while (!qAuxClass.isEmpty()) {
				id = qAuxClass.dequeue();
				table->insertVariable(id, type, access);
			}	
			stackO.push(table->getLast().memoryDirection);						
		}
		
}

void Parser::VAR_CLASE() {
		if (la->kind == 78) {
			Get();
			int temp = stackO.pop();
			const wchar_t* aux = sType.pop();
			
		} else if (la->kind == 79) {
			ASIGNACION();
			Expect(78);
		} else SynErr(94);
}

void Parser::CONSTRUCTOR() {
		variablesTable *vars;
		queue<const wchar_t*> *params;
		
		Expect(5);
		Expect(1);
		if(!procDir->exist(t->val, L"constructor")) {
		currentProc = t->val;
		
														params = new queue<const wchar_t*>;
		
														vars = new variablesTable::variablesTable(contProc++, BASE_MEM, MEM_JUNK_SIZE);
														variablesTable *obj = new variablesTable::variablesTable(vars->contInt, vars->contFloat, vars->contBoolet, vars->contChar); 
		
														variablesTable *attributes = procDir->getElement(L"global").varTable;
														attributes->insertIntoTable(obj);
		
														vars->insertObject(L"returnObject", currentClass, L"public", *obj);
		
														procDir->insertProcedure(t->val, L"public", false, currentClass, *params, L"constructor", *vars, code.getCounter());
		//												code.insertCuadruplo(19, -1, -1, contProc++);
														
		//												code.insertCuadruplo(20, -1, -1, -1);
		
														contTemp[0] = BASE_TEMP;
														contTemp[1] = BASE_TEMP + TEMP_JUNK_SIZE;
														contTemp[2] = BASE_TEMP + (2 * TEMP_JUNK_SIZE);
														contTemp[3] = BASE_TEMP + (3 * TEMP_JUNK_SIZE);
													} else {
														wcout << L"ERROR. El metodo constructor " << t->val << " ya existe.\n";
													}
												
		CONSTRUCTOR1();
		int cInt = vars->contInt;
		int cFloat = vars->contFloat;
		int cBoolet = vars->contBoolet;
		int cChar = vars->contChar;
		while(!qAuxParams.isEmpty()) {
			const wchar_t* paramId = qAuxParams.dequeue();
			const wchar_t* paramType = qAuxClass.dequeue();
			params->enqueue(paramType);
			if(!wcscmp(paramType,L"int")) {
				code.insertCuadruplo(13, contTemp[0]++, -1, cInt++);
			} else if (!wcscmp(paramType, L"float")) {
				code.insertCuadruplo(13, contTemp[1]++, -1, cFloat++);
			} else if (!wcscmp(paramType, L"boolet")) {
				code.insertCuadruplo(13, contTemp[2]++, -1, cBoolet++);
			} else if (!wcscmp(paramType, L"char")) {
				code.insertCuadruplo(13, contTemp[3]++, -1, cChar++);
			}
			vars->insertVariable(paramId, paramType, L"public");
		//												code.insertCuadruplo(-1,-1,-1,-1);
													}
													varTable = vars;
												
		Expect(74);
		BLOQUE();
		queue<int> paramDirections = procDir->getElement(L"global").varTable->getDirections();
		queue<int> returnDirections = procDir->getElement(currentProc).varTable->getElement(L"returnObject").object->getDirections();
		while (!paramDirections.isEmpty()) {
			code.insertCuadruplo(13, paramDirections.dequeue(), -1, returnDirections.dequeue());
		}
		
		Expect(75);
}

void Parser::METODO() {
		variablesTable *vars;
		queue<const wchar_t*> *params;
		
		Expect(6);
		Expect(1);
		if(!procDir->exist(t->val, L"procedure")) {
		currentProc = t->val;
		vars = new variablesTable::variablesTable(contProc++, BASE_MEM, MEM_JUNK_SIZE);
		
											vars->insertVariable(L"returnInt", L"int", L"public");
											vars->insertVariable(L"returnFloat", L"float", L"public");
											vars->insertVariable(L"returnBoolet", L"boolet", L"public");
											vars->insertVariable(L"returnChar", L"char", L"public");
		
											params = new queue<const wchar_t*>;
		
										} else {
											wcout << L"ERROR. El metodo " << t->val << " ya existe.\n";
										}
									
		METODO1();
		bool isStatic;
		if (!wcscmp(t->val, L"static")) {
			isStatic = true;
		} else {
			isStatic = false;
		}
		
		METODO2();
		METODO3();
		METODO4();
		const wchar_t* access = qAuxClass.dequeue();
		const wchar_t* returns = qAuxClass.dequeue();
		
												contTemp[0] = BASE_TEMP;
												contTemp[1] = BASE_TEMP + TEMP_JUNK_SIZE;
												contTemp[2] = BASE_TEMP + (2 * TEMP_JUNK_SIZE);
												contTemp[3] = BASE_TEMP + (3 * TEMP_JUNK_SIZE);
		
												procDir->insertProcedure(currentProc, access, isStatic, returns, *params, L"procedure", *vars,code.getCounter());
		//										code.insertCuadruplo(19, -1, -1, contProc++);
			//									code.insertCuadruplo(20, -1, -1, -1);
												int cInt = vars->contInt;
												int cFloat = vars->contFloat;
												int cBoolet = vars->contBoolet;
												int cChar = vars->contChar;
												while(!qAuxParams.isEmpty()){
													const wchar_t* paramId = qAuxParams.dequeue();
													const wchar_t* paramType = qAuxClass.dequeue();
													params->enqueue(paramType);
													if(!wcscmp(paramType,L"int")) {
														code.insertCuadruplo(13, contTemp[0]++, -1, cInt++);
													} else if (!wcscmp(paramType, L"float")) {
														code.insertCuadruplo(13, contTemp[1]++, -1, cFloat++);
													} else if (!wcscmp(paramType, L"boolet")) {
														code.insertCuadruplo(13, contTemp[2]++, -1, cBoolet++);
													} else if (!wcscmp(paramType, L"char")) {
														code.insertCuadruplo(13, contTemp[3]++, -1, cChar++);
													}
													vars->insertVariable(paramId, paramType, L"public");
		//											code.insertCuadruplo(-1,-1,-1,-1);
												}
												varTable = vars;
											
		Expect(74);
		BLOQUE();
		Expect(75);
}

void Parser::BLOQUE() {
		if (StartOf(2)) {
			ESTATUTO();
			BLOQUE();
		} else if (la->kind == 75) {
		} else SynErr(95);
}

void Parser::DECLARACION_VARIABLES2() {
		if (la->kind == 8 || la->kind == 9) {
			if (la->kind == 9) {
				Get();
			} else {
				Get();
			}
			qAuxClass.enqueue(t->val);
			
		} else if (StartOf(3)) {
			qAuxClass.enqueue(L"public");
			
		} else SynErr(96);
}

void Parser::S_TIPO() {
		if (StartOf(4)) {
			S_TIPO1();
			TIPO();
		} else if (la->kind == 1) {
			Get();
			if(classDir.exist(t->val, L"id")) {
			qAuxClass.enqueue(L"object");
			qAuxClass.enqueue(t->val);
			}
			
		} else SynErr(97);
}

void Parser::DECLARACION_VARIABLES1() {
		if (la->kind == 70) {
			Get();
			Expect(1);
			variablesTable *table = procDir->getElement(currentProc).varTable;
			if (!table->exist(t->val)) {
				qAuxClass.enqueue(t->val);
			} else {
				wcout << L"ERROR. La variable "<< t->val << L" ya existe\n";
			}
			
			DECLARACION_VARIABLES1();
		} else if (la->kind == 78 || la->kind == 79) {
		} else SynErr(98);
}

void Parser::ASIGNACION() {
		variablesTable *attributes;
		
		variablesTable *table = procDir->getElement(currentProc).varTable;
		if (classDir.exist(table->getElement(t->val).type, L"id")) {
		
											attributes = table->getElement(t->val).object;
		//									sType.push(table->getElement(t->val).type);	
										}
									
		Expect(79);
		sOper.push(t->val);
		S_EXPRESION();
		if(!sOper.isEmpty()) {
		const wchar_t* operador = sOper.topEL();
		if(!wcscmp(operador, L":D")) {
		
												operador = sOper.pop();
		
												const wchar_t* t2 = sType.pop();
												const wchar_t* t1 = sType.pop();
		
												const wchar_t* typeR = cube.ask(t1,operador,t2);
												if(wcscmp(typeR,L"int") && wcscmp(typeR,L"float") && wcscmp(typeR,L"boolet") && wcscmp(typeR,L"char")) {
													procedureDirectory *pdir = classDir.getElement(t1).procDir;
													variablesTable *temp = pdir->getElement(sConstructor.pop()).varTable;
													variablesTable *aux = temp->getElement(0).object;
		
													int i = 0;
													variablesTable::variableInfo info = attributes->getElement(i);
													variablesTable::variableInfo auxInfo = aux->getElement(i);
		
													const wchar_t* j = attributes->getLast().id;
		
													while(wcscmp(j,info.id)) {
														code.insertCuadruplo(13, auxInfo.memoryDirection, -1, info.memoryDirection);
				
														i++;
														info = attributes->getElement(i);
														auxInfo = aux->getElement(i);
													}
														code.insertCuadruplo(13, auxInfo.memoryDirection, -1, info.memoryDirection);
												} else {
		
													int op2 = stackO.pop();
													int op1 = stackO.pop();
		
													if (!wcscmp(typeR,L"Error")) {
														wcout << "Operacion no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error1")) {
														wcout << "Operacion entre los dos objetos no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error2")) {
														wcout << "Ambos objetos son de diferente tipo\n";
													}
													else if (!wcscmp(typeR,L"Error3")) {
														wcout << "Uno de los operandos es un objeto\n";
													}
													else if (!wcscmp(typeR,L"Error4")) {
														wcout << "Operador inexistente\n";
													}
													else {
														code.insertCuadruplo(13, op2, -1, op1);
													}
												}
											} 
										}
								  
}

void Parser::ESTATUTO() {
		if (la->kind == 25) {
			BUCLE();
		} else if (la->kind == 32) {
			CONDICION();
		} else if (la->kind == 37) {
			JUMP();
		} else if (StartOf(5)) {
			ESTATUTO1();
			Expect(78);
		} else SynErr(99);
}

void Parser::CONSTRUCTOR1() {
		if (la->kind == 20) {
			RECIBE_PARAMETROS();
		} else if (la->kind == 74) {
		} else SynErr(100);
}

void Parser::RECIBE_PARAMETROS() {
		Expect(20);
		Expect(21);
		Expect(76);
		S_TIPO();
		Expect(1);
		qAuxParams.enqueue(t->val);
		
		RECIBE_PARAMETROS1();
		Expect(77);
}

void Parser::METODO1() {
		if (la->kind == 7) {
			Get();
		} else if (StartOf(6)) {
		} else SynErr(101);
}

void Parser::METODO2() {
		if (la->kind == 8 || la->kind == 9) {
			if (la->kind == 9) {
				Get();
			} else {
				Get();
			}
			qAuxClass.enqueue(t->val);
			
		} else if (la->kind == 11 || la->kind == 20 || la->kind == 74) {
			qAuxClass.enqueue(L"public");
			
		} else SynErr(102);
}

void Parser::METODO3() {
		if (la->kind == 11) {
			Get();
			Expect(76);
			S_TIPO();
			Expect(77);
		} else if (la->kind == 20 || la->kind == 74) {
			qAuxClass.enqueue(L"");
			
		} else SynErr(103);
}

void Parser::METODO4() {
		if (la->kind == 20) {
			RECIBE_PARAMETROS();
		} else if (la->kind == 74) {
		} else SynErr(104);
}

void Parser::S_TIPO1() {
		if (la->kind == 13) {
			LIST();
		} else if (StartOf(7)) {
		} else SynErr(105);
}

void Parser::TIPO() {
		if (la->kind == 15) {
			Get();
		} else if (la->kind == 16) {
			Get();
		} else if (la->kind == 17) {
			Get();
		} else if (la->kind == 18) {
			Get();
		} else SynErr(106);
		qAuxClass.enqueue(t->val); 
}

void Parser::LIST() {
		Expect(13);
		qAuxClass.enqueue(L"list"); 
		LIST1();
		Expect(14);
}

void Parser::LIST1() {
		Expect(76);
		M_EXPRESION();
		const wchar_t* type = sType.pop();
		if (type == L"int") {
			auxListLength = stackO.pop();
		} else {
			wcout << L"ERROR. Se esperaba un entero para definir el tama??o de la lista.\n";
		}
		
		Expect(77);
}

void Parser::M_EXPRESION() {
		M_EXPRESION1();
		EXPRESION();
		if (!sOper.isEmpty()) {
		const wchar_t* operador = sOper.topEL();
		if(!wcscmp(operador, L"NOT")) {
			int op1 = stackO.pop();
			operador = sOper.pop();
			const wchar_t* t1 = sType.pop();
		
														const wchar_t* typeR = cube.ask(t1,operador,L"-1");
														if (!wcscmp(typeR,L"Error")) {
															wcout << "Operacion no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error1")) {
															wcout << "Operacion entre los dos objetos no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error2")) {
															wcout << "Ambos objetos son de diferente tipo\n";
														}
														else if (!wcscmp(typeR,L"Error3")) {
															wcout << "Uno de los operandos es un objeto\n";
														}
														else if (!wcscmp(typeR,L"Error4")) {
															wcout << "Operador inexistente\n";
														}
														else {
															int result = contTemp[2]++;
															code.insertCuadruplo(14, op1, -1, result);
															stackO.push(result);
															sType.push(typeR);
														}
		
													}
												}
												
		M_EXPRESION2();
}

void Parser::RECIBE_PARAMETROS1() {
		if (la->kind == 70) {
			Get();
			S_TIPO();
			Expect(1);
			qAuxParams.enqueue(t->val);
			
			RECIBE_PARAMETROS1();
		} else if (la->kind == 77) {
		} else SynErr(107);
}

void Parser::BUCLE() {
		int increment = constantTable.insert(1);
		
		Expect(25);
		Expect(26);
		BUCLE1();
		Expect(74);
		BLOQUE_BUCLE();
		Expect(75);
		int comienzo;
		if(auxLoop) {
			int temporal = sJump.pop();
			comienzo = code.getCounter();
			code.insertCuadruplo(1, temporal, increment, temporal);
			code.insertCuadruplo(16, -1, -1, sJump.pop());
			code.fillCuadruplo(sJump.pop(),code.getCounter());
		} else {
			int condicion = sJump.pop();
			int brinco = sJump.pop();
		
										code.insertCuadruplo(16, -1, -1, brinco);
										code.fillCuadruplo(condicion, code.getCounter());
										
										comienzo = qContinue.dequeue();								
									}
									while (!qBreak.isEmpty()) {
										code.fillCuadruplo(qBreak.dequeue(), code.getCounter());
									}
		
									while (!qContinue.isEmpty()) {
										code.fillCuadruplo(qContinue.dequeue(), comienzo);
									}
								
}

void Parser::CONDICION() {
		int condicion;
		const wchar_t* type1;
		
		Expect(32);
		Expect(76);
		M_EXPRESION();
		condicion = stackO.pop();
		type1 = sType.pop();
		if(!wcscmp(type1,L"boolet")) {	
			sJumpIf.push(code.getCounter());
			code.insertCuadruplo(27,condicion,-1,-1);
		} else{
			wcout << L"ERROR. Esperaba un valor logico para la condicion.\n";
		}												
		
		Expect(77);
		Expect(33);
		Expect(74);
		BLOQUE_BREAK();
		Expect(75);
		CONDICION1();
		while (!qBreak.isEmpty()) {
		code.fillCuadruplo(qBreak.dequeue(), code.getCounter());
		}
		
}

void Parser::JUMP() {
		Expect(37);
		Expect(38);
		Expect(76);
		S_EXPRESION();
		Expect(77);
		Expect(39);
		Expect(74);
		JUMP1();
		Expect(41);
		Expect(72);
		BLOQUE();
		Expect(75);
}

void Parser::ESTATUTO1() {
		switch (la->kind) {
		case 1: case 12: {
			ESTATUTO2();
			break;
		}
		case 52: {
			INVOCACION();
			break;
		}
		case 47: {
			ESCRITURA();
			break;
		}
		case 48: {
			BORRAR_DE_LISTA();
			break;
		}
		case 50: {
			PUSH();
			break;
		}
		case 51: {
			ESTATUTO_RETURN();
			break;
		}
		case 42: {
			SET_LISTA();
			break;
		}
		default: SynErr(108); break;
		}
}

void Parser::ESTATUTO2() {
		if (la->kind == 1) {
			C_ID();
			ASIGNACION();
		} else if (la->kind == 12) {
			DECLARACION_VARIABLES();
			ESTATUTO3();
		} else SynErr(109);
}

void Parser::INVOCACION() {
		const wchar_t* id;
		variablesTable *vars;
		queue<const wchar_t*> *params;
		queue<int> paramDirections;
		int procDirection;
		procedureInfo info;
		queue<int> objMet1;
		queue<int> objMet2;
		
		Expect(52);
		Expect(1);
		id = t-> val;
		
		if (la->kind == 71) {
			Get();
			Expect(1);
			if(classDir.exist(id, L"id")) {
			procedureDirectory *dir = classDir.getElement(id).procDir;
			if(!wcscmp(classDir.getElement(id).id,L"")) {
				wcout << L"ERROR. La clase " << id << L" no existe.\n";
			}
			
													info = dir->getElement(t->val);
			
													if(!wcscmp(info.id,L"")) {
														wcout << L"ERROR. El metodo " << t->val << L" no existe.\n";
													}
			
													if (wcscmp(info.whatKind, L"procedure")) {
														wcout << L"ERROR. " << t->val << L" no es un metodo.\n";
													}
			
													if (info.isStatic) {
														procDirection = info.cuadruplo;
														paramDirections = info.varTable->getDirections();
														params = info.parametersTypes;
														code.insertCuadruplo(19, -1, -1, dir->getElement(L"global").varTable->procFactor);
				//										code.insertCuadruplo(20,-1,-1,-1);
														code.insertCuadruplo(23, -1, -1, dir->getElement(L"global").cuadruplo);
														code.insertCuadruplo(19, -1, -1, info.varTable->procFactor);
						//								code.insertCuadruplo(20,-1,-1,-1);
													} else {
														wcout << L"ERROR. El metodo al que se intento acceder no es estatico.\n";
													}
			
												//object.method
												} else {
													const wchar_t* type = varTable->getElement(id).type;
													if (!wcscmp(type,L"")) {
														wcout << L"ERROR. La variable " << id << L" no existe.\n";
													}
			
													procedureDirectory *dir = classDir.getElement(type).procDir;
													if (!wcscmp(classDir.getElement(type).id,L"")) {
														wcout << L"ERROR. La variable " << id << L" no es un objeto.\n";
													}
			
													info = dir->getElement(t->val);
													if (!wcscmp(info.whatKind, L"procedure")) {
														objMet = true;
														procDirection = info.cuadruplo;
														params = info.parametersTypes;
														paramDirections = info.varTable->getDirections();
														code.insertCuadruplo(19, -1, -1, info.varTable->procFactor);
				//										code.insertCuadruplo(20,-1,-1,-1);
			
														vars = dir->getElement(L"global").varTable;
														queue<int> directions = vars->getDirections();
														variablesTable *attributes = varTable->getElement(id).object;
														queue<int> values = attributes->getDirections();
														while(!directions.isEmpty()) {
															if (!values.isEmpty()) {
																code.insertCuadruplo(13, values.front(), -1, directions.front());
																objMet1.enqueue(values.dequeue());
																objMet2.enqueue(directions.dequeue());
															} else {
																wcout << L"ERROR. Faltan mas argumentos.\n";
															}
														}
														if (!values.isEmpty()) {
															wcout << L"ERROR. Sobran argumentos.\n";
														}
													} else {
														wcout << L"ERROR. La variable " << t->val << L" no es un procedimiento de la clase " << type << L".\n";
													}
												}
											
		} else if (StartOf(8)) {
			if(!wcscmp(procDir->getElement(id).id, L"")) {
			wcout << L"El metodo " << id << L" no existe en esta clase.\n";
			} else {
				info = procDir->getElement(id);
				if (wcscmp(info.whatKind, L"procedure")) {
					wcout << L"ERROR. El metodo " << t->val << L" no existe.\n";
				}
				if (wcscmp(info.whatKind, L"procedure")) {
					wcout << L"ERROR. " << t->val << L" no es un metodo.\n";
				}
				code.insertCuadruplo(19, -1, -1, info.varTable->procFactor);
			//							code.insertCuadruplo(20,-1,-1,-1);
										paramDirections = info.varTable->getDirections();
										procDirection = info.cuadruplo;
										params = info.parametersTypes;				
									}
								
		} else SynErr(110);
		INVOCACION1();
		variablesTable *tableVar = procDir->getElement(currentProc).varTable;
		queue<int> directionsParam = tableVar->getDirections();
		queue<const wchar_t*> tempParams = tableVar->getTypes();
		int numParam = procDir->getElement(currentProc).parametersTypes->getSize();
		int numParam1 = numParam;
		//									queue<const wchar_t*> *auxParams = procDir->getElement(currentProc).parametersTypes;
			//								auxParams->insertIntoQueue(tempParams);
				//							if (auxParams->isEmpty()) {
					//							wcout << currentProc << L"\n";
						//					}
											int intSalvation = contTemp[0];
											int floatSalvation = contTemp[1];
											int booletSalvation = contTemp[2];
											int charSalvation = contTemp[3];
											while (numParam > 0) {
												const wchar_t* paramTypes = tempParams.dequeue();
												if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, directionsParam.dequeue(), -1, contTemp[0]++);
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, directionsParam.dequeue(), -1, contTemp[1]++);
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, directionsParam.dequeue(), -1, contTemp[2]++);
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, directionsParam.dequeue(), -1, contTemp[3]++);
												}
												numParam--;
											}
											//despues, enviamos los argumentos como parametros al metodo a invocar
											int i = procDirection;
											const wchar_t* paramType;
											int cInt = BASE_TEMP;
											int cFloat = cInt + TEMP_JUNK_SIZE;
											int cBoolet = cFloat + TEMP_JUNK_SIZE;
											int cChar = cBoolet + TEMP_JUNK_SIZE;
											while(!qAuxArgs.isEmpty()) {
												paramType = qAuxParams.front();
												if(!wcscmp(qAuxParams.dequeue(),params->dequeue())) {
		
													if(!wcscmp(paramType,L"int")) {
														code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cInt++);
													} else if (!wcscmp(paramType, L"float")) {
														code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cFloat++);
													} else if (!wcscmp(paramType, L"boolet")) {
														code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cBoolet++);
													} else if (!wcscmp(paramType, L"char")) {
														code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cChar++);
													}
		
		//										code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, paramDirections.dequeue());
												} else {
													wcout << L"ERROR. Incongruencia en tipos de datos entre parametros y argumentos.\n";
												}
											}
				
											//asginamos una direccion para valores a retornar
											variablesTable *vars1 = info.varTable;
											if (!wcscmp(info.returns, L"int")) {
												stackO.push(vars1->getElement(L"returnInt").memoryDirection);
												sType.push(L"int");
											} else if (!wcscmp(info.returns, L"float")) {
												stackO.push(vars1->getElement(L"returnFloat").memoryDirection);
												sType.push(L"float");
											} else if (!wcscmp(info.returns, L"boolet")) {
												stackO.push(vars1->getElement(L"returnBoolet").memoryDirection);
												sType.push(L"boolet");
											} else if (!wcscmp(info.returns, L"char")) {
												stackO.push(vars1->getElement(L"returnChar").memoryDirection);
												sType.push(L"char");
											}
			
											//gosub al metodo
											code.insertCuadruplo(23, -1, -1, procDirection);
		
											if (objMet) {
												objMet = false;
												while (!objMet1.isEmpty()) {
													code.insertCuadruplo(13, objMet2.dequeue(), -1, objMet1.dequeue());
												}
											}
		
											//finalmente, recuperamos los valores de los parametros del metodo actual
											tempParams = tableVar->getTypes();
											directionsParam = tableVar->getDirections();
											while (numParam1 > 0) {
												const wchar_t* paramTypes = tempParams.dequeue();
												if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, intSalvation++, -1, directionsParam.dequeue());
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, floatSalvation++, -1, directionsParam.dequeue());
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, booletSalvation++, -1, directionsParam.dequeue());
												} else if (!wcscmp(paramTypes, L"int")) {
													code.insertCuadruplo(13, charSalvation++, -1, directionsParam.dequeue());
												}
												numParam1--;
											}
										
}

void Parser::ESCRITURA() {
		Expect(47);
		Expect(76);
		ESCRITURA1();
		Expect(77);
}

void Parser::BORRAR_DE_LISTA() {
		Expect(48);
		Expect(43);
		Expect(49);
		EXP();
		Expect(45);
		C_ID();
}

void Parser::PUSH() {
		Expect(50);
		S_EXPRESION();
		Expect(39);
		STRING();
}

void Parser::ESTATUTO_RETURN() {
		Expect(51);
		S_EXPRESION();
		int result = stackO.pop();
		const wchar_t* type = sType.topEL();
		procedureInfo info = procDir->getElement(currentProc);
		const wchar_t* returns = info.returns;
		if (!wcscmp(type, returns)) {
			int tempReturn;
			variablesTable *vars = info.varTable;
		
															int base = BASE_MEM + (vars->procFactor * (4 * MEM_JUNK_SIZE));
		
															if(!wcscmp(returns, L"int")) {
																tempReturn = base;
															} else if(!wcscmp(returns, L"float")) {
																tempReturn = base + MEM_JUNK_SIZE;
															} else if(!wcscmp(returns, L"boolet")) {
																tempReturn =  base + (MEM_JUNK_SIZE * 2);
															} else if(!wcscmp(returns, L"char")) {
																tempReturn =  base + (MEM_JUNK_SIZE * 3);
															} else {
																tempReturn = -1;
															}					
															code.insertCuadruplo(13, result, -1, tempReturn);
															code.insertCuadruplo(24,-1,-1,-1);
															
														} else {
															wcout << L"ERROR. Incongruencia entre el tipo de dato retornado y el requerido. \n";
														}		
													
}

void Parser::SET_LISTA() {
		Expect(42);
		Expect(43);
		Expect(44);
		M_EXPRESION();
		Expect(45);
		C_ID();
		Expect(46);
		S_EXPRESION();
}

void Parser::C_ID() {
		const wchar_t* cid;
		const wchar_t* cid1;
		
		Expect(1);
		cid1 = t->val;
		
		if (la->kind == 71) {
			Get();
			Expect(1);
			cid = t->val;
			stackO.push(0);
			sType.push(L"int");								
			variablesTable *table = procDir->getVarObject(cid1, currentProc);
			if (table != 0) {
				if (wcscmp(table->getElement(cid).id, L"")) {
					stackO.push(table->getElement(cid).memoryDirection);
					sType.push(table->getElement(cid).type);								
				} else {
					wcout << L"ERROR. No existe el atributo" << cid << L" para el objeto " << cid1 << endl;
				}
			} else {
				wcout << L"ERROR. No existe el objecto " << cid1 << endl;
			}
			
		} else if (StartOf(9)) {
			cid = t->val;
			const wchar_t* type = procDir->getVarType(cid, currentProc);
			if (wcscmp(type, L"")) {
				if (!wcscmp(type, L"int") || !wcscmp(type, L"float") || !wcscmp(type, L"boolet") || !wcscmp(type, L"char")) {	
					stackO.push(procDir->getVarLocation(cid, currentProc));
				}
				sType.push(type);
			} else {
				wcout << L"ERROR. La variable "<< cid << " no existe.\n";
			}
			
		} else SynErr(111);
}

void Parser::ESTATUTO3() {
		if (la->kind == 79) {
			ASIGNACION();
		} else if (la->kind == 78) {
		} else SynErr(112);
}

void Parser::S_EXPRESION() {
		if (la->kind == 57) {
			LECTURA();
		} else if (la->kind == 55) {
			GET_LISTA();
		} else if (la->kind == 56) {
			POP();
		} else if (StartOf(10)) {
			STRING();
		} else SynErr(113);
}

void Parser::LECTURA() {
		Expect(57);
		if (la->kind == 15) {
			Get();
			code.insertCuadruplo(25,contTemp[0],-1,-1);
			stackO.push(contTemp[0]++);
			sType.push(L"int");
			
		} else if (la->kind == 16) {
			Get();
			code.insertCuadruplo(26,contTemp[1],-1,-1);
			stackO.push(contTemp[1]++);
			sType.push(L"float");
			
		} else if (la->kind == 18) {
			Get();
			code.insertCuadruplo(28,contTemp[2],-1,-1);
			stackO.push(contTemp[2]++);
			sType.push(L"boolet");
			
		} else if (la->kind == 17) {
			Get();
			code.insertCuadruplo(29,contTemp[3],-1,-1);
			stackO.push(contTemp[3]++);
			sType.push(L"char");
			/*								code.insertCuadruplo(18,-1,-1, contTemp[3]);
											stackO.push(contTemp[3]++);
											sType.push(L"list");
			*/
													
		} else SynErr(114);
}

void Parser::GET_LISTA() {
		Expect(55);
		Expect(43);
		Expect(44);
		M_EXPRESION();
		Expect(45);
		C_ID();
}

void Parser::POP() {
		Expect(56);
		Expect(45);
		STRING();
}

void Parser::STRING() {
		STRING1();
		STRING2();
}

void Parser::PARAMETRO() {
		S_EXPRESION();
		qAuxArgs.enqueue(stackO.pop());
		qAuxParams.enqueue(sType.pop());
		
		PARAMETRO2();
}

void Parser::PARAMETRO2() {
		if (la->kind == 70) {
			Get();
			PARAMETRO();
		} else if (la->kind == 77) {
		} else SynErr(115);
}

void Parser::BUCLE1() {
		int condicion;
		const wchar_t* type1;
		
		if (StartOf(11)) {
			EXP();
			auxLoop = true;
			int times = stackO.pop();
			const wchar_t* type = sType.pop();
			if(!wcscmp(type,L"int")) {
				int temporal = contTemp[0]++;
				code.insertCuadruplo(13, times, -1, temporal);
				sJump.push(code.getCounter() + 1);
				sJump.push(code.getCounter());
				int aux = constantTable.insert(0);
				int temporal1 = contTemp[2]++;
				code.insertCuadruplo(4, temporal, aux, temporal1);
				code.insertCuadruplo(27, temporal1, -1, -1);
				sJump.push(temporal);
			} else {
				wcout << L"ERROR. Esperaba valor entero para las iteraciones.\n";
			}
			
			Expect(28);
		} else if (la->kind == 27) {
			Get();
			Expect(76);
			auxLoop = false;
			sJump.push(code.getCounter());
			qContinue.enqueue(code.getCounter());
			
			M_EXPRESION();
			condicion = stackO.pop();
			type1 = sType.pop();
			if(!wcscmp(type1,L"boolet")) {	
				sJump.push(code.getCounter());
				code.insertCuadruplo(27,condicion,-1,-1);
			} else{
				wcout << L"ERROR. Esperaba un valor logico para la condicion.\n";
			}						
			
			Expect(77);
		} else SynErr(116);
}

void Parser::BLOQUE_BUCLE() {
		if (StartOf(12)) {
			if (StartOf(2)) {
				ESTATUTO();
			} else {
				BLOQUE_BUCLE1();
			}
			BLOQUE_BUCLE();
		} else if (la->kind == 75) {
		} else SynErr(117);
}

void Parser::EXP() {
		TERMINO();
		if (!sOper.isEmpty()) {
		const wchar_t* operador = sOper.topEL();
		if(!wcscmp(operador, L"+") || !wcscmp(operador, L"-")) {
			int op2 = stackO.pop();
			int op1 = stackO.pop();
			operador = sOper.pop();
			const wchar_t* t2 = sType.pop();
			const wchar_t* t1 = sType.pop();
		
												const wchar_t* typeR = cube.ask(t1,operador,t2);
												if (!wcscmp(typeR,L"Error")) {
													wcout << "Operacion no soportada\n";
												}
												else if (!wcscmp(typeR,L"Error1")) {
													wcout << "Operacion entre los dos objetos no soportada\n";
												}
												else if (!wcscmp(typeR,L"Error2")) {
													wcout << "Ambos objetos son de diferente tipo\n";
												}
												else if (!wcscmp(typeR,L"Error3")) {
													wcout << "Uno de los operandos es un objeto\n";
												}
												else if (!wcscmp(typeR,L"Error4")) {
													wcout << "Operador inexistente\n";
												}
												else {
													int result;
													if(!wcscmp(typeR, L"int")) {
														result = contTemp[0]++;
													} else {
														result = contTemp[1]++;
													}
													code.insertCuadruplo(operador, op1, op2, result);
													stackO.push(result);
													sType.push(typeR);
												}
											}
										}
										
		EXP1();
}

void Parser::BLOQUE_BREAK() {
		if (StartOf(13)) {
			if (StartOf(2)) {
				ESTATUTO();
			} else {
				BLOQUE_BREAK1();
			}
			BLOQUE_BREAK();
		} else if (la->kind == 40 || la->kind == 41 || la->kind == 75) {
		} else SynErr(118);
}

void Parser::CONDICION1() {
		if (la->kind == 34) {
			Get();
			code.insertCuadruplo(16, -1, -1, -1);
			code.fillCuadruplo(sJumpIf.pop(), code.getCounter());	
			sJumpIf.push(code.getCounter() - 1);	
			
			CONDICION2();
		} else if (StartOf(14)) {
			while (!sJumpIf.isEmpty()) {
			code.fillCuadruplo(sJumpIf.pop(), code.getCounter());	
			}
			
		} else SynErr(119);
}

void Parser::CONDICION2() {
		if (la->kind == 32) {
			CONDICION();
		} else if (la->kind == 33) {
			Get();
			Expect(74);
			BLOQUE_BREAK();
			Expect(75);
			while (!sJumpIf.isEmpty()) {
			code.fillCuadruplo(sJumpIf.pop(), code.getCounter());	
			}									
			
		} else SynErr(120);
}

void Parser::BLOQUE_BUCLE1() {
		BLOQUE_BUCLE2();
		Expect(78);
}

void Parser::BLOQUE_BUCLE2() {
		if (la->kind == 35) {
			Get();
			qContinue.enqueue(code.getCounter());
			code.insertCuadruplo(16, -1, -1, -1);
			
		} else if (la->kind == 36) {
			Get();
			qBreak.enqueue(code.getCounter());
			code.insertCuadruplo(16, -1, -1, -1);
			
		} else SynErr(121);
}

void Parser::JUMP1() {
		if (la->kind == 40) {
			Get();
			Expect(76);
			S_EXPRESION();
			JUMP2();
			Expect(77);
			Expect(72);
			BLOQUE_BREAK();
			JUMP1();
		} else if (la->kind == 41) {
		} else SynErr(122);
}

void Parser::JUMP2() {
		if (la->kind == 73) {
			Get();
			S_EXPRESION();
			JUMP2();
		} else if (la->kind == 77) {
		} else SynErr(123);
}

void Parser::BLOQUE_BREAK1() {
		Expect(36);
		qBreak.enqueue(code.getCounter());
		code.insertCuadruplo(16, -1, -1, -1);
		
		Expect(78);
}

void Parser::ESCRITURA1() {
		STRING();
		int msj = stackO.pop();
		const wchar_t* type = sType.pop();
		code.insertCuadruplo(17,msj,-1,-1);
		
		ESCRITURA2();
}

void Parser::ESCRITURA2() {
		if (la->kind == 70) {
			Get();
			ESCRITURA1();
		} else if (la->kind == 77) {
		} else SynErr(124);
}

void Parser::INVOCACION1() {
		if (la->kind == 53) {
			Get();
			Expect(54);
			Expect(76);
			PARAMETRO();
			Expect(77);
		} else if (StartOf(15)) {
		} else SynErr(125);
}

void Parser::INSTANCIACION() {
		procedureDirectory *dir;	
		procedureInfo info;
		queue<int> paramDirections;
		int procDirection;
		queue<const wchar_t*> *params;
		
		Expect(58);
		Expect(1);
		if(classDir.exist(t->val, L"id")) {
		dir = classDir.getElement(t->val).procDir;
		code.insertCuadruplo(19,-1,-1, dir->getElement(L"global").varTable->procFactor);
		code.insertCuadruplo(23,-1,-1, dir->getElement(L"global").cuadruplo);
		} else {
			wcout << L"ERROR. No existen objetos de tipo " << t->val << L".\n";
		}
		
		Expect(59);
		Expect(1);
		info = dir->getElement(t->val);
		if(wcscmp(info.id, L"")) {
			sConstructor.push(t->val);
			paramDirections = info.varTable->getDirections();
			procDirection = info.cuadruplo;
			params = info.parametersTypes;								
			code.insertCuadruplo(19,-1,-1,info.varTable->procFactor);
		} else {
			wcout << L"ERROR. No existe el constructor " << t->val << L"\n";
		}
		
		INSTANCIACION1();
		int i = procDirection;
		const wchar_t* paramType;
		int cInt = BASE_TEMP;
		int cFloat = cInt + TEMP_JUNK_SIZE;
		int cBoolet = cFloat + TEMP_JUNK_SIZE;
		int cChar = cBoolet + TEMP_JUNK_SIZE;
		while(!qAuxArgs.isEmpty()) {
			paramType = qAuxParams.front();
			if(!wcscmp(qAuxParams.dequeue(),params->dequeue())) {
				if(!wcscmp(paramType,L"int")) {
					code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cInt++);
				} else if (!wcscmp(paramType, L"float")) {
					code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cFloat++);
				} else if (!wcscmp(paramType, L"boolet")) {
					code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cBoolet++);
				} else if (!wcscmp(paramType, L"char")) {
					code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, cChar++);
				}
		
		//										code.insertCuadruplo(13, qAuxArgs.dequeue(), -1, paramDirections.dequeue());
												} else {
													wcout << L"ERROR. Incongruencia en tipos de datos entre parametros y argumentos.\n";
												}
											}
				
											//asginamos una direccion para valores a retornar
		//									variablesTable *vars1 = info.varTable->getElement(L"returnObject").object;
											sType.push(info.varTable->getElement(L"returnObject").type);
		/*									queue<const wchar_t*> returnTypes = vars1->getTypes();
											queue<int> returnDirections = vars1->getDirections();
											while (!returnDirections.isEmpty()) {
												if (!wcscmp(returnTypes.dequeue(), L"int")) {
													stackO.push(vars1->getElement(L"returnInt").memoryDirection);
												} else if (!wcscmp(returnTypes.dequeue(), L"float")) {
													stackO.push(vars1->getElement(L"returnFloat").memoryDirection);
												} else if (!wcscmp(returnTypes.dequeue(), L"boolet")) {
													stackO.push(vars1->getElement(L"returnBoolet").memoryDirection);
												} else if (!wcscmp(returnTypes.dequeue(), L"char")) {
													stackO.push(vars1->getElement(L"returnChar").memoryDirection);
												}
											}
			*/								//gosub al metodo
											code.insertCuadruplo(23, -1, -1, procDirection);
											
}

void Parser::INSTANCIACION1() {
		if (la->kind == 53) {
			Get();
			Expect(60);
			Expect(76);
			PARAMETRO();
			Expect(77);
		} else if (StartOf(15)) {
		} else SynErr(126);
}

void Parser::STRING1() {
		if (la->kind == 64 || la->kind == 74) {
			ESTRUCTURA_LISTA();
		} else if (la->kind == 63) {
			Get();
			char tmp, comilla;
			swscanf(t->val, L"%c%c",&comilla,&tmp); 
			int aux = constantTable.insert(tmp); 
			stackO.push(aux);
			sType.push(L"char");
			
		} else if (StartOf(16)) {
			M_EXPRESION();
		} else SynErr(127);
}

void Parser::STRING2() {
		if (la->kind == 69) {
			Get();
			STRING();
		} else if (StartOf(17)) {
		} else SynErr(128);
}

void Parser::ESTRUCTURA_LISTA() {
		if (la->kind == 74) {
			Get();
			ESTRUCTURA_LISTA1();
			Expect(75);
		} else if (la->kind == 64) {
			Get();
		} else SynErr(129);
}

void Parser::ESTRUCTURA_LISTA1() {
		if (StartOf(18)) {
			S_EXPRESION();
			ESTRUCTURA_LISTA2();
		} else if (la->kind == 75) {
		} else SynErr(130);
}

void Parser::ESTRUCTURA_LISTA2() {
		if (la->kind == 70) {
			Get();
			ESTRUCTURA_LISTA1();
		} else if (la->kind == 75) {
		} else SynErr(131);
}

void Parser::M_EXPRESION1() {
		if (la->kind == 22) {
			Get();
			sOper.push(t->val); 
		} else if (StartOf(11)) {
		} else SynErr(132);
}

void Parser::EXPRESION() {
		EXP();
		EXPRESION1();
}

void Parser::M_EXPRESION2() {
		if (la->kind == 23) {
			Get();
			sOper.push(t->val); 
			M_EXPRESION();
			if (!sOper.isEmpty()) {
			const wchar_t* operador = sOper.topEL();
			if(!wcscmp(operador, L"AND")) {
				int op2 = stackO.pop();
				int op1 = stackO.pop();
				operador = sOper.pop();
				const wchar_t* t2 = sType.pop();
				const wchar_t* t1 = sType.pop();
			
													const wchar_t* typeR = cube.ask(t1,operador,t2);
													if (!wcscmp(typeR,L"Error")) {
														wcout << "Operacion no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error1")) {
														wcout << "Operacion entre los dos objetos no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error2")) {
														wcout << "Ambos objetos son de diferente tipo\n";
													}
													else if (!wcscmp(typeR,L"Error3")) {
														wcout << "Uno de los operandos es un objeto\n";
													}
													else if (!wcscmp(typeR,L"Error4")) {
														wcout << "Operador inexistente\n";
													}
													else {
														int result = contTemp[2]++;
														code.insertCuadruplo(10, op1, op2, result);
														stackO.push(result);
														sType.push(typeR);
													}
												}
											 }
											
		} else if (la->kind == 24) {
			Get();
			sOper.push(t->val); 
			M_EXPRESION();
			if (!sOper.isEmpty()) {
			const wchar_t* operador = sOper.topEL();
			if(!wcscmp(operador, L"OR")) {
				int op2 = stackO.pop();
				int op1 = stackO.pop();
				operador = sOper.pop();
				const wchar_t* t2 = sType.pop();
				const wchar_t* t1 = sType.pop();
			
													const wchar_t* typeR = cube.ask(t1,operador,t2);
													if (!wcscmp(typeR,L"Error")) {
														wcout << "Operacion no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error1")) {
														wcout << "Operacion entre los dos objetos no soportada\n";
													}
													else if (!wcscmp(typeR,L"Error2")) {
														wcout << "Ambos objetos son de diferente tipo\n";
													}
													else if (!wcscmp(typeR,L"Error3")) {
														wcout << "Uno de los operandos es un objeto\n";
													}
													else if (!wcscmp(typeR,L"Error4")) {
														wcout << "Operador inexistente\n";
													}
													else {
														int result = contTemp[2]++;
														code.insertCuadruplo(10, op1, op2, result);
														stackO.push(result);
														sType.push(typeR);
													}
												}
											}
											
		} else if (StartOf(19)) {
		} else SynErr(133);
}

void Parser::EXPRESION1() {
		if (StartOf(20)) {
			EXPRESION2();
			EXP();
			if (!sOper.isEmpty()) {
			const wchar_t* operador = sOper.topEL();
			if(!wcscmp(operador, L"<") || !wcscmp(operador, L">") || !wcscmp(operador, L"<>") || !wcscmp(operador, L":<") || !wcscmp(operador, L":>") || !wcscmp(operador, L":{")) {
				int op2 = stackO.pop();
				int op1 = stackO.pop();
				operador = sOper.pop();
				const wchar_t* t2 = sType.pop();
				const wchar_t* t1 = sType.pop();
			
														const wchar_t* typeR = cube.ask(t1,operador,t2);
														if (!wcscmp(typeR,L"Error")) {
															wcout << "Operacion no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error1")) {
															wcout << "Operacion entre los dos objetos no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error2")) {
															wcout << "Ambos objetos son de diferente tipo\n";
														}
														else if (!wcscmp(typeR,L"Error3")) {
															wcout << "Uno de los operandos es un objeto\n";
														}
														else if (!wcscmp(typeR,L"Error4")) {
															wcout << "Operador inexistente\n";
														}
														else {
															int result = contTemp[2]++;
															code.insertCuadruplo(operador, op1, op2, result);
															stackO.push(result);
															sType.push(typeR);
														}
			
													}
												}
												
		} else if (StartOf(21)) {
		} else SynErr(134);
}

void Parser::EXPRESION2() {
		switch (la->kind) {
		case 81: {
			Get();
			break;
		}
		case 80: {
			Get();
			break;
		}
		case 82: {
			Get();
			break;
		}
		case 83: {
			Get();
			break;
		}
		case 84: {
			Get();
			break;
		}
		case 85: {
			Get();
			break;
		}
		default: SynErr(135); break;
		}
		sOper.push(t->val);	
}

void Parser::TERMINO() {
		FACTOR();
		if (!sOper.isEmpty()) {
		const wchar_t* operador = sOper.topEL();
		if(!wcscmp(operador, L"*") || !wcscmp(operador, L"/")) {
			int op2 = stackO.pop();
			int op1 = stackO.pop();
			operador = sOper.pop();
			const wchar_t* t2 = sType.pop();
			const wchar_t* t1 = sType.pop();
		
												const wchar_t* typeR = cube.ask(t1,operador,t2);
												if (!wcscmp(typeR,L"Error")) {
													wcout << "Operacion no soportada\n";
												}
												else if (!wcscmp(typeR,L"Error1")) {
													wcout << "Operacion entre los dos objetos no soportada\n";
												}
												else if (!wcscmp(typeR,L"Error2")) {
													wcout << "Ambos objetos son de diferente tipo\n";
												}
												else if (!wcscmp(typeR,L"Error3")) {
													wcout << "Uno de los operandos es un objeto\n";
												}
												else if (!wcscmp(typeR,L"Error4")) {
													wcout << "Operador inexistente\n";
												}
												else {
													int result;
													if(!wcscmp(typeR, L"int")) {
														result = contTemp[0]++;
													} else {
														result = contTemp[1]++;
													}
													code.insertCuadruplo(operador, op1, op2, result);
													stackO.push(result);
													sType.push(typeR);
												}
											}
										}
										
		TERMINO1();
}

void Parser::EXP1() {
		if (la->kind == 65 || la->kind == 66) {
			EXP2();
			EXP();
		} else if (StartOf(22)) {
		} else SynErr(136);
}

void Parser::EXP2() {
		if (la->kind == 65) {
			Get();
		} else if (la->kind == 66) {
			Get();
		} else SynErr(137);
		sOper.push(t->val);
		
}

void Parser::FACTOR() {
		if (la->kind == 76) {
			Get();
			M_EXPRESION();
			Expect(77);
		} else if (StartOf(23)) {
			FACTOR1();
			VAR_NUM();
			if (!sOper.isEmpty()) {
			const wchar_t* operador = sOper.topEL();
			if (!wcscmp(operador, L"NEG")) {
				int op1 = stackO.pop();
				operador = sOper.pop();
				const wchar_t* t1 = sType.pop();
			
														const wchar_t* typeR = cube.ask(t1,operador,L"-1");
														if (!wcscmp(typeR,L"Error")) {
															wcout << "Operacion no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error1")) {
															wcout << "Operacion entre los dos objetos no soportada\n";
														}
														else if (!wcscmp(typeR,L"Error2")) {
															wcout << "Ambos objetos son de diferente tipo\n";
														}
														else if (!wcscmp(typeR,L"Error3")) {
															wcout << "Uno de los operandos es un objeto\n";
														}
														else if (!wcscmp(typeR,L"Error4")) {
															wcout << "Operador inexistente\n";
														}
														else {
															int result;
															if(!wcscmp(typeR, L"int")) {
																result = contTemp[0]++;
															} else {
																result = contTemp[1]++;
															}
															code.insertCuadruplo(15, op1, -1, result);
															stackO.push(result);
															sType.push(typeR);
														}
													}
												}
												
		} else SynErr(138);
}

void Parser::TERMINO1() {
		if (la->kind == 67 || la->kind == 68) {
			TERMINO2();
			TERMINO();
		} else if (StartOf(24)) {
		} else SynErr(139);
}

void Parser::TERMINO2() {
		if (la->kind == 67) {
			Get();
		} else if (la->kind == 68) {
			Get();
		} else SynErr(140);
		sOper.push(t->val);
		
}

void Parser::FACTOR1() {
		if (la->kind == 66) {
			Get();
			sOper.push(L"NEG");
			
		} else if (StartOf(25)) {
		} else SynErr(141);
}

void Parser::VAR_NUM() {
		switch (la->kind) {
		case 62: {
			Get();
			int tmp;
			swscanf(t->val, L"%d",&tmp); 
			int aux = constantTable.insert(tmp); 
			stackO.push(aux);
			sType.push(L"int");
			
			break;
		}
		case 61: {
			Get();
			float tmp;
			swscanf(t->val, L"%f",&tmp);
			int aux = constantTable.insert(tmp);
			stackO.push(aux); 
			sType.push(L"float");
			
			break;
		}
		case 86: {
			Get();
			int aux = constantTable.insert(true);
			stackO.push(aux); 
			sType.push(L"boolet");
			
			break;
		}
		case 87: {
			Get();
			int aux = constantTable.insert(false);
			stackO.push(aux); 
			sType.push(L"boolet");
			
			break;
		}
		case 1: {
			C_ID();
			break;
		}
		case 52: {
			INVOCACION();
			break;
		}
		case 58: {
			INSTANCIACION();
			break;
		}
		default: SynErr(142); break;
		}
}



void Parser::Parse() {
	t = NULL;
	la = dummyToken = new Token();
	la->val = coco_string_create(L"Dummy Token");
	Get();
	coffeec();

	Expect(0);
}

Parser::Parser(Scanner *scanner) {
	maxT = 88;

	dummyToken = NULL;
	t = la = NULL;
	minErrDist = 2;
	errDist = minErrDist;
	this->scanner = scanner;
	errors = new Errors();
}

bool Parser::StartOf(int s) {
	const bool T = true;
	const bool x = false;

	static bool set[26][90] = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,T,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, T,x,x,x, x,T,x,x, x,x,T,x, x,x,x,T, T,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,T,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,T,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,T, T,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, T,T,x,T, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,x, x,T,x,T, x,T,T,x, T,T,T,T, T,T,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,x, x,T,x,T, x,T,T,T, T,T,T,T, T,T,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,T,x, x,T,T,T, T,x,T,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,T,T, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,T,x, x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,T,T, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, T,x,x,T, T,T,x,x, x,x,T,x, x,x,x,T, T,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, T,x,x,x, T,T,x,x, x,x,T,x, x,x,x,T, T,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,T,x,x, x,x,x,x, T,x,x,T, T,T,x,x, T,T,T,x, x,x,x,T, T,x,T,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,T, T,T,T,x, x,T,x,T, x,T,T,x, T,T,T,T, T,T,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,T,x, x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,x,x, x,x,T,T, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,T,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, T,T,T,x, x,T,T,T, T,x,T,x, x,x,x,x, x,x,T,x, T,x,x,x, x,x,x,x, x,x,T,T, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,T,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,T,T, T,T,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,T,x,T, x,T,T,x, x,x,x,x, x,x,x,x, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,T,x,T, x,T,T,x, T,T,T,T, T,T,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,T,x, x,T,T,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x},
		{x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, T,x,x,x, T,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,T,T,x, x,T,T,x, x,T,x,T, x,T,T,x, T,T,T,T, T,T,x,x, x,x},
		{x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, x,x,T,x, x,T,T,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, x,x}
	};



	return set[s][la->kind];
}

Parser::~Parser() {
	delete errors;
	delete dummyToken;
}

Errors::Errors() {
	count = 0;
}

void Errors::SynErr(int line, int col, int n) {
	wchar_t* s;
	switch (n) {
			case 0: s = coco_string_create(L"EOF expected"); break;
			case 1: s = coco_string_create(L"id expected"); break;
			case 2: s = coco_string_create(L"main expected"); break;
			case 3: s = coco_string_create(L"class expected"); break;
			case 4: s = coco_string_create(L"inherits expected"); break;
			case 5: s = coco_string_create(L"constructor expected"); break;
			case 6: s = coco_string_create(L"method expected"); break;
			case 7: s = coco_string_create(L"static expected"); break;
			case 8: s = coco_string_create(L"private expected"); break;
			case 9: s = coco_string_create(L"public expected"); break;
			case 10: s = coco_string_create(L"global expected"); break;
			case 11: s = coco_string_create(L"returns expected"); break;
			case 12: s = coco_string_create(L"var expected"); break;
			case 13: s = coco_string_create(L"list expected"); break;
			case 14: s = coco_string_create(L"of expected"); break;
			case 15: s = coco_string_create(L"int expected"); break;
			case 16: s = coco_string_create(L"float expected"); break;
			case 17: s = coco_string_create(L"char expected"); break;
			case 18: s = coco_string_create(L"boolet expected"); break;
			case 19: s = coco_string_create(L"equis expected"); break;
			case 20: s = coco_string_create(L"receives expected"); break;
			case 21: s = coco_string_create(L"parameters expected"); break;
			case 22: s = coco_string_create(L"not expected"); break;
			case 23: s = coco_string_create(L"and expected"); break;
			case 24: s = coco_string_create(L"or expected"); break;
			case 25: s = coco_string_create(L"fruit expected"); break;
			case 26: s = coco_string_create(L"loop expected"); break;
			case 27: s = coco_string_create(L"until expected"); break;
			case 28: s = coco_string_create(L"times expected"); break;
			case 29: s = coco_string_create(L"starting expected"); break;
			case 30: s = coco_string_create(L"the expected"); break;
			case 31: s = coco_string_create(L"iteration expected"); break;
			case 32: s = coco_string_create(L"when expected"); break;
			case 33: s = coco_string_create(L"do expected"); break;
			case 34: s = coco_string_create(L"otherwise expected"); break;
			case 35: s = coco_string_create(L"continue expected"); break;
			case 36: s = coco_string_create(L"breakdance expected"); break;
			case 37: s = coco_string_create(L"jump expected"); break;
			case 38: s = coco_string_create(L"on expected"); break;
			case 39: s = coco_string_create(L"to expected"); break;
			case 40: s = coco_string_create(L"case expected"); break;
			case 41: s = coco_string_create(L"default expected"); break;
			case 42: s = coco_string_create(L"set expected"); break;
			case 43: s = coco_string_create(L"element expected"); break;
			case 44: s = coco_string_create(L"gato expected"); break;
			case 45: s = coco_string_create(L"from expected"); break;
			case 46: s = coco_string_create(L"as expected"); break;
			case 47: s = coco_string_create(L"print expected"); break;
			case 48: s = coco_string_create(L"remove expected"); break;
			case 49: s = coco_string_create(L"at expected"); break;
			case 50: s = coco_string_create(L"push expected"); break;
			case 51: s = coco_string_create(L"return expected"); break;
			case 52: s = coco_string_create(L"call expected"); break;
			case 53: s = coco_string_create(L"with expected"); break;
			case 54: s = coco_string_create(L"arguments expected"); break;
			case 55: s = coco_string_create(L"get expected"); break;
			case 56: s = coco_string_create(L"pop expected"); break;
			case 57: s = coco_string_create(L"read expected"); break;
			case 58: s = coco_string_create(L"make expected"); break;
			case 59: s = coco_string_create(L"via expected"); break;
			case 60: s = coco_string_create(L"attributes expected"); break;
			case 61: s = coco_string_create(L"cte_f expected"); break;
			case 62: s = coco_string_create(L"cte_i expected"); break;
			case 63: s = coco_string_create(L"cte_char expected"); break;
			case 64: s = coco_string_create(L"string_comillas expected"); break;
			case 65: s = coco_string_create(L"mas expected"); break;
			case 66: s = coco_string_create(L"menos expected"); break;
			case 67: s = coco_string_create(L"multiplicacion expected"); break;
			case 68: s = coco_string_create(L"division expected"); break;
			case 69: s = coco_string_create(L"concatenacion expected"); break;
			case 70: s = coco_string_create(L"coma expected"); break;
			case 71: s = coco_string_create(L"punto expected"); break;
			case 72: s = coco_string_create(L"dos_puntos expected"); break;
			case 73: s = coco_string_create(L"pipe expected"); break;
			case 74: s = coco_string_create(L"abre_llaves expected"); break;
			case 75: s = coco_string_create(L"cierra_llaves expected"); break;
			case 76: s = coco_string_create(L"abre_parentesis expected"); break;
			case 77: s = coco_string_create(L"cierra_parentesis expected"); break;
			case 78: s = coco_string_create(L"delimitador expected"); break;
			case 79: s = coco_string_create(L"igual expected"); break;
			case 80: s = coco_string_create(L"mayor expected"); break;
			case 81: s = coco_string_create(L"menor expected"); break;
			case 82: s = coco_string_create(L"distinto expected"); break;
			case 83: s = coco_string_create(L"menor_igual expected"); break;
			case 84: s = coco_string_create(L"mayor_igual expected"); break;
			case 85: s = coco_string_create(L"comparacion expected"); break;
			case 86: s = coco_string_create(L"verdadero expected"); break;
			case 87: s = coco_string_create(L"falso expected"); break;
			case 88: s = coco_string_create(L"??? expected"); break;
			case 89: s = coco_string_create(L"invalid COFFEEC1"); break;
			case 90: s = coco_string_create(L"invalid CLASE1"); break;
			case 91: s = coco_string_create(L"invalid CLASE2"); break;
			case 92: s = coco_string_create(L"invalid CLASE3"); break;
			case 93: s = coco_string_create(L"invalid DECLARACION_CLASE1"); break;
			case 94: s = coco_string_create(L"invalid VAR_CLASE"); break;
			case 95: s = coco_string_create(L"invalid BLOQUE"); break;
			case 96: s = coco_string_create(L"invalid DECLARACION_VARIABLES2"); break;
			case 97: s = coco_string_create(L"invalid S_TIPO"); break;
			case 98: s = coco_string_create(L"invalid DECLARACION_VARIABLES1"); break;
			case 99: s = coco_string_create(L"invalid ESTATUTO"); break;
			case 100: s = coco_string_create(L"invalid CONSTRUCTOR1"); break;
			case 101: s = coco_string_create(L"invalid METODO1"); break;
			case 102: s = coco_string_create(L"invalid METODO2"); break;
			case 103: s = coco_string_create(L"invalid METODO3"); break;
			case 104: s = coco_string_create(L"invalid METODO4"); break;
			case 105: s = coco_string_create(L"invalid S_TIPO1"); break;
			case 106: s = coco_string_create(L"invalid TIPO"); break;
			case 107: s = coco_string_create(L"invalid RECIBE_PARAMETROS1"); break;
			case 108: s = coco_string_create(L"invalid ESTATUTO1"); break;
			case 109: s = coco_string_create(L"invalid ESTATUTO2"); break;
			case 110: s = coco_string_create(L"invalid INVOCACION"); break;
			case 111: s = coco_string_create(L"invalid C_ID"); break;
			case 112: s = coco_string_create(L"invalid ESTATUTO3"); break;
			case 113: s = coco_string_create(L"invalid S_EXPRESION"); break;
			case 114: s = coco_string_create(L"invalid LECTURA"); break;
			case 115: s = coco_string_create(L"invalid PARAMETRO2"); break;
			case 116: s = coco_string_create(L"invalid BUCLE1"); break;
			case 117: s = coco_string_create(L"invalid BLOQUE_BUCLE"); break;
			case 118: s = coco_string_create(L"invalid BLOQUE_BREAK"); break;
			case 119: s = coco_string_create(L"invalid CONDICION1"); break;
			case 120: s = coco_string_create(L"invalid CONDICION2"); break;
			case 121: s = coco_string_create(L"invalid BLOQUE_BUCLE2"); break;
			case 122: s = coco_string_create(L"invalid JUMP1"); break;
			case 123: s = coco_string_create(L"invalid JUMP2"); break;
			case 124: s = coco_string_create(L"invalid ESCRITURA2"); break;
			case 125: s = coco_string_create(L"invalid INVOCACION1"); break;
			case 126: s = coco_string_create(L"invalid INSTANCIACION1"); break;
			case 127: s = coco_string_create(L"invalid STRING1"); break;
			case 128: s = coco_string_create(L"invalid STRING2"); break;
			case 129: s = coco_string_create(L"invalid ESTRUCTURA_LISTA"); break;
			case 130: s = coco_string_create(L"invalid ESTRUCTURA_LISTA1"); break;
			case 131: s = coco_string_create(L"invalid ESTRUCTURA_LISTA2"); break;
			case 132: s = coco_string_create(L"invalid M_EXPRESION1"); break;
			case 133: s = coco_string_create(L"invalid M_EXPRESION2"); break;
			case 134: s = coco_string_create(L"invalid EXPRESION1"); break;
			case 135: s = coco_string_create(L"invalid EXPRESION2"); break;
			case 136: s = coco_string_create(L"invalid EXP1"); break;
			case 137: s = coco_string_create(L"invalid EXP2"); break;
			case 138: s = coco_string_create(L"invalid FACTOR"); break;
			case 139: s = coco_string_create(L"invalid TERMINO1"); break;
			case 140: s = coco_string_create(L"invalid TERMINO2"); break;
			case 141: s = coco_string_create(L"invalid FACTOR1"); break;
			case 142: s = coco_string_create(L"invalid VAR_NUM"); break;

		default:
		{
			wchar_t format[20];
			coco_swprintf(format, 20, L"error %d", n);
			s = coco_string_create(format);
		}
		break;
	}
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
	coco_string_delete(s);
	count++;
}

void Errors::Error(int line, int col, const wchar_t *s) {
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
	count++;
}

void Errors::Warning(int line, int col, const wchar_t *s) {
	wprintf(L"-- line %d col %d: %ls\n", line, col, s);
}

void Errors::Warning(const wchar_t *s) {
	wprintf(L"%ls\n", s);
}

void Errors::Exception(const wchar_t* s) {
	wprintf(L"%ls", s); 
	exit(1);
}



